var globeRadius = 1000;
var vec3_origin = new THREE.Vector3(0,0,0);
var RTOD = 57.295779513082320876798154814;
var DTOR = 0.0174532925199432957692369077;

function isZero (value) {
	return ((value<1e-13) && (value>-1e-13));
}

function constrain(v, min, max){
	if( v < min )
		v = min;
	else
	if( v > max )
		v = max;
	return v;
}

function lerpSelf (v1,  v2, alpha ) {

	v1.x += ( v2.x - v1.x ) * alpha;
	v1.y += ( v2.y - v1.y ) * alpha;
	v1.z += ( v2.z - v1.z ) * alpha;

	return v1;
}

function addSelf (v1,  v2 ) {

	v1.x += v2.x;
	v1.y += v2.y;
	v1.z += v2.z;

	return v1;
}

function sphericalToCartesian (dLongitude, dLatitude, dRadius) {
	var dRadCosLat = dRadius * Math.cos(dLatitude);
	return new THREE.Vector3(dRadCosLat*Math.sin(dLongitude), dRadius*Math.sin(dLatitude), dRadCosLat*Math.cos(dLongitude));
}

function cartesianToSpherical (x, y, z) {
	var rho = Math.sqrt(x * x + y * y + z * z);
	if (isZero(rho))
	{
		return new THREE.Vector3(0, 0, 0);
	}
	var longitude = Math.atan2(x, z);
	var latitude = Math.asin(y / rho);
	return new THREE.Vector3(longitude, latitude, rho);
}

function createLineGeometry ( points ) {
	var geometry = new THREE.Geometry();
	for( var i = 0; i < points.length; i ++ ) {
		geometry.vertices.push( points[i] );
	}
	return geometry;
};


function makeConnectionLinePoints( startPoint, endPoint, value, radius, type ){

	var start = startPoint;
	var end = endPoint;
	start = sphericalToCartesian (startPoint.x * DTOR, startPoint.y * DTOR, radius);
	end = sphericalToCartesian (endPoint.x * DTOR, endPoint.y * DTOR, radius);

	var normal = (new THREE.Vector3()).sub(start, end);

	var distanceBetweenCountryCenter = normal.length();

	//	how high we want to shoot the curve upwards
	var anchorHeight = globeRadius + distanceBetweenCountryCenter * 0.7;

	//	midpoint for the curve
	var mid = lerpSelf(start.clone(), end, 0.5);
	var midLength = mid.length()
	mid.normalize();
	mid.multiplyScalar( midLength + distanceBetweenCountryCenter * 0.7 );

	//	the normal from start to end
	normal.normalize();

	/*
	 The curve looks like this:

	 midStartAnchor---- mid ----- midEndAnchor
	 /											  \
	 /											   \
	 /												\
	 start/anchor 										 end/anchor

	 splineCurveA							splineCurveB
	 */

	var distanceHalf = distanceBetweenCountryCenter * 0.5;

	var startAnchor = start;
	var midStartAnchor = addSelf( mid.clone(), normal.clone().multiplyScalar( distanceHalf ) );
	var midEndAnchor = addSelf( mid.clone(), normal.clone().multiplyScalar( -distanceHalf ) );
	var endAnchor = end;

	//	now make a bezier curve out of the above like so in the diagram
	var splineCurveA = new THREE.CubicBezierCurve3( start, startAnchor, midStartAnchor, mid);
	// splineCurveA.updateArcLengths();

	var splineCurveB = new THREE.CubicBezierCurve3( mid, midEndAnchor, endAnchor, end);
	// splineCurveB.updateArcLengths();

	//	how many vertices do we want on this guy? this is for *each* side
	var vertexCountDesired = Math.floor( /*splineCurveA.getLength()*/ distanceBetweenCountryCenter * 0.02 + 6 ) * 2;

	//	collect the vertices
	var points = splineCurveA.getPoints( vertexCountDesired );

	//	remove the very last point since it will be duplicated on the next half of the curve
	points = points.splice(0,points.length-1);

	points = points.concat( splineCurveB.getPoints( vertexCountDesired ) );

	//	add one final point to the center of the earth
	//	we need this for drawing multiple arcs, but piled into one geometry buffer
	//points.push( vec3_origin );

	if (type == 1) {
		for (var i = 0; i < points.length; i++) {
			var position = cartesianToSpherical (points[i].x, points[i].y, points[i].z);
			points[i] = new THREE.Vector3(10 * position.x * RTOD, 10 * position.y * RTOD, (position.z - radius));
		}
	}

	var val = value * 0.0003;
	var size = (10 + Math.sqrt(val));
	size = constrain(size,0.1, 60);
	points.size = size;

	return points;
}


function makeConnectionLineGeometry( startPoint, endPoint, value, radius, type ){

	var points = makeConnectionLinePoints( startPoint, endPoint, value, radius, type );
	var curveGeometry = createLineGeometry( points );
	curveGeometry.size = points.size;
	return curveGeometry;
}

